package com.cliff.mdns;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;

import javax.jmdns.JmDNS;
import javax.jmdns.ServiceEvent;
import javax.jmdns.ServiceListener;
import javax.jmdns.ServiceTypeListener;

import android.app.ExpandableListActivity;
import android.content.Context;
import android.database.DataSetObserver;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiManager.MulticastLock;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.StrictMode;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.TextView;

public class MainActivity extends ExpandableListActivity {

	protected MulticastLock lock;
	protected final String MULTICAST_LOCK = "cliff_box_multicastlock";
	protected JmDNS jmdns = null;
	protected ServiceListener listener;
	protected final String TAG = "MainActivity";
//	protected final String UNIVERSAL_TYPE = "_services._dns-sd._udp.local.";
	
	protected ArrayList<ServiceEvent> serviceTypeList = new ArrayList<ServiceEvent>();
	protected ArrayList<ArrayList<ServiceEvent>> serviceArrayList = new ArrayList<ArrayList<ServiceEvent>>();
	protected MDnsListAdapter adapter = null;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
//		setContentView(R.layout.activity_main);
		adapter = new MDnsListAdapter(this);
		setListAdapter(adapter);
		DisplayMetrics dm = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(dm);
        int width = dm.widthPixels;
 
        getExpandableListView().setIndicatorBounds(width - getDipsFromPixel(35), width
                - getDipsFromPixel(5));

		StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
		StrictMode.setThreadPolicy(policy); 
		
		WifiManager wifi = (WifiManager)getSystemService(android.content.Context.WIFI_SERVICE);
		lock = wifi.createMulticastLock(MULTICAST_LOCK);
	    lock.setReferenceCounted(true);
	    lock.acquire();
	    
	    initJmDns();
	}
	
	public int getDipsFromPixel(float pixels) {
        // Get the screen's density scale
        final float scale = getResources().getDisplayMetrics().density;
        // Convert the dps to pixels, based on density scale
        return (int) (pixels * scale + 0.5f);
    }	

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}
	
	@Override
	protected void onDestroy() {
		// TODO Auto-generated method stub
		if (null != jmdns) {
			try {
				jmdns.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
        if (null != lock) lock.release();

        super.onDestroy();
	}
	
	protected void initJmDns() {
		try {
			jmdns = JmDNS.create();
			jmdns.addServiceTypeListener(new ServiceTypeListener(){
				@Override
				public void serviceTypeAdded(ServiceEvent event) {
		            Log.d(TAG, "serviceTypeAdded: " + event.getType());
		            
				    jmdns.addServiceListener(event.getType(), new MDnsServiceListener(serviceTypeList.size()));
				    serviceTypeList.add(event);
				    serviceArrayList.add(new ArrayList<ServiceEvent>());
				    adapter.refresh();
				}

				@Override
				public void subTypeForServiceTypeAdded(ServiceEvent event) {
		            Log.d(TAG, "subTypeForServiceTypeAdded: "+ event.getType());										
				}				
			});	
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	protected class MDnsServiceListener implements ServiceListener {
		protected int parentId = 0;
		
		public MDnsServiceListener(int id) {
			parentId = id;
		}

		@Override
		public void serviceAdded(ServiceEvent event) {
        	Log.d(TAG, "serviceAdded : " + event.getName());
            jmdns.requestServiceInfo(event.getType(), event.getName(), 1);			
		}

		@Override
		public void serviceRemoved(ServiceEvent event) {
        	Log.d(TAG, "serviceRemoved: " + event.getName());
        	ArrayList<ServiceEvent> serviceList = serviceArrayList.get(parentId);
        	for (ServiceEvent eventInList:serviceList) {
        		if (eventInList.getName().equals(event.getName())) {
        			serviceList.remove(eventInList);
        			break;
        		}
        	}
		    adapter.refresh();
		}

		@Override
		public void serviceResolved(ServiceEvent event) {
            Log.d(TAG, "serviceResolved: "
                    + event.getInfo().getQualifiedName()
                    + " port:" + event.getInfo().getPort());
            serviceArrayList.get(parentId).add(event);            
		    adapter.refresh();
		}		
	};

	protected class MDnsListAdapter extends BaseExpandableListAdapter {
		protected Handler handler;
		protected Context context;
		
		public MDnsListAdapter(Context context) {  
	        this.context = context;  
	        handler = new Handler(){  	  
	            @Override  
	            public void handleMessage(Message msg) {  
	              notifyDataSetChanged();  
	              super.handleMessage(msg);  
	            }  
	        };  
	    }  
	      
	    public void refresh() {  
	        handler.sendMessage(new Message());  
	    }  
		@Override
		public void registerDataSetObserver(DataSetObserver observer) {
			// TODO Auto-generated method stub
			super.registerDataSetObserver(observer);
		}

		@Override
		public Object getChild(int arg0, int arg1) {
			return serviceArrayList.get(arg0).get(arg1);
		}

		@Override
		public long getChildId(int arg0, int arg1) {
			return arg1;
		}

		@Override
		public View getChildView(int arg0, int arg1, boolean arg2, View arg3,
				ViewGroup parent) {
			
			LayoutInflater inflater = (LayoutInflater) MainActivity.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
			View rowView = inflater.inflate(android.R.layout.simple_list_item_2, parent, false);
		    TextView text1 = (TextView) rowView.findViewById(android.R.id.text1);
		    TextView text2 = (TextView) rowView.findViewById(android.R.id.text2);
		    text1.setText(serviceArrayList.get(arg0).get(arg1).getName());
		    String[] hostAddress = serviceArrayList.get(arg0).get(arg1).getInfo().getHostAddresses();
		    if ((null == hostAddress)||(0 == hostAddress.length))
		    	text2.setText("No Host Address");
		    else
		    	text2.setText(hostAddress[0]);
			return rowView;
		}

		@Override
		public int getChildrenCount(int arg0) {			
			return serviceArrayList.get(arg0).size();
		}

		@Override
		public Object getGroup(int arg0) {
			
			return serviceTypeList.get(arg0);
		}

		@Override
		public int getGroupCount() {
			return serviceTypeList.size();
		}

		@Override
		public long getGroupId(int arg0) {
			return arg0;
		}

		@Override
		public View getGroupView(int arg0, boolean arg1, View arg2,
				ViewGroup parent) {
			LayoutInflater inflater = (LayoutInflater) MainActivity.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
			View rowView = inflater.inflate(android.R.layout.simple_list_item_1, parent, false);
		    TextView text1 = (TextView) rowView.findViewById(android.R.id.text1);
//		    TextView text2 = (TextView) rowView.findViewById(android.R.id.text2);
		    text1.setText(serviceTypeList.get(arg0).getType()+"("+serviceArrayList.get(arg0).size()+")");
//		    text2.setText(serviceTypeList.get(arg0).getName());
			return rowView;
		}

		@Override
		public boolean hasStableIds() {
			return false;
		}

		@Override
		public boolean isChildSelectable(int arg0, int arg1) {
			return false;
		}
		
	}

}
